Перейти к основному содержимому

Простые приложения на JavaScript

Разработчику Архитектору

Простые приложения на JavaScript

JavaScript — это язык программирования, который изначально создавался для работы в веб-браузерах. Сегодня он является универсальным инструментом, позволяющим создавать серверные приложения, утилиты командной строки и сложные системы автоматизации благодаря среде выполнения Node.js.

В этой главе рассматриваются базовые задачи, решаемые с помощью JavaScript. Каждый пример демонстрирует конкретный аспект языка: работу со строками, файловой системой, сетевыми протоколами или данными. Код приводится в виде модульных скриптов, готовых к запуску в среде Node.js.

Генератор паролей

Генератор паролей демонстрирует манипуляции со строковыми типами данных, использование массивов символов и генерацию случайных значений.

Основные концепции

  • Массивы: Хранение наборов символов (буквы, цифры, спецсимволы).
  • Строки: Формирование итогового результата путем конкатенации.
  • Случайность: Использование встроенного объекта Math для выбора случайного индекса.
  • Функции: Инкапсуляция логики в переиспользуемый блок кода.

Пример кода

/**
* Генератор безопасных паролей
* @param {number} length - Длина пароля
* @param {boolean} useDigits - Включать ли цифры
* @param {boolean} useSymbols - Включать ли специальные символы
* @returns {string} Сгенерированный пароль
*/
function generatePassword(length = 12, useDigits = true, useSymbols = true) {
const lowercaseChars = 'abcdefghijklmnopqrstuvwxyz';
const uppercaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const digitChars = '0123456789';
const symbolChars = '!@#$%^&*()_+-=[]{}|;:,.<>?';

let charPool = lowercaseChars + uppercaseChars;

if (useDigits) {
charPool += digitChars;
}

if (useSymbols) {
charPool += symbolChars;
}

let password = '';

// Гарантируем наличие хотя бы одного символа каждого типа при включении опций
if (useDigits && length > 0) {
password += digitChars[Math.floor(Math.random() * digitChars.length)];
length--;
}

if (useSymbols && length > 0) {
password += symbolChars[Math.floor(Math.random() * symbolChars.length)];
length--;
}

// Заполняем оставшуюся длину случайными символами из общего пула
for (let i = 0; i < length; i++) {
const randomIndex = Math.floor(Math.random() * charPool.length);
password += charPool[randomIndex];
}

// Перемешиваем строку, чтобы гарантированный символ не всегда был первым
return password.split('').sort(() => 0.5 - Math.random()).join('');
}

// Пример использования
const myPassword = generatePassword(16, true, true);
console.log(`Сгенерированный пароль: ${myPassword}`);

Разбор логики

Скрипт формирует строковый пул символов на основе выбранных параметров. Цикл for выбирает случайные индексы из этого пула и добавляет соответствующие символы в итоговую строку. Метод split, sort и join используется для перемешивания символов, что повышает криптографическую стойкость пароля по сравнению с простым последовательным добавлением.


Сортировщик текстового файла

Этот пример показывает работу с файловым вводом/выводом, обработку строк и алгоритмы сортировки списков.

Основные концепции

  • Модуль fs: Чтение и запись файлов в дисковой системе.
  • Обработка ошибок: Блоки try...catch для обработки ситуаций, когда файл отсутствует или недоступен.
  • Методы массивов: split, filter, sort для трансформации данных.
  • Асинхронность: Использование промисов (Promise) для неблокирующего чтения файлов.

Пример кода

const fs = require('fs').promises;

async function sortTextFile(inputPath, outputPath) {
try {
// Чтение содержимого файла
const data = await fs.readFile(inputPath, 'utf-8');

// Разбиение текста на строки и фильтрация пустых строк
const lines = data.split('\n')
.map(line => line.trim())
.filter(line => line.length > 0);

// Сортировка строк в алфавитном порядке
const sortedLines = lines.sort((a, b) => a.localeCompare(b));

// Объединение отсортированных строк обратно в текст
const result = sortedLines.join('\n');

// Запись результата в новый файл
await fs.writeFile(outputPath, result, 'utf-8');

console.log(`Успешно обработано строк: ${sortedLines.length}`);
console.log(`Результат сохранен в: ${outputPath}`);
} catch (error) {
console.error('Ошибка при обработке файла:', error.message);
}
}

// Пример вызова
// sortTextFile('input.txt', 'output_sorted.txt');

Разбор логики

Функция readFile загружает весь файл в память как строку. Метод split('\n') разбивает текст на массив строк. Операция trim() удаляет лишние пробелы по краям каждой строки. Алгоритм localeCompare обеспечивает корректную сортировку с учетом правил языка (например, русские буквы сортируются правильно). Результат записывается в целевой файл методом writeFile.


Консольный калькулятор

Калькулятор иллюстрирует работу с пользовательским вводом, условную логику и базовые математические операции.

Основные концепции

  • Парсинг ввода: Преобразование строковых данных пользователя в числовые значения.
  • Условные конструкции: Выбор действия в зависимости от оператора.
  • Обработка деления на ноль: Защита от критических ошибок вычислений.
  • Циклы: Многократное выполнение операций до команды выхода.

Пример кода

function calculate(num1, num2, operator) {
switch (operator) {
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
case '/':
if (num2 === 0) {
throw new Error('Деление на ноль невозможно');
}
return num1 / num2;
default:
throw new Error(`Неизвестный оператор: ${operator}`);
}
}

async function runCalculator() {
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});

const question = (query) => new Promise(resolve => readline.question(query, resolve));

while (true) {
console.log('\n=== Калькулятор ===');
console.log('Доступные операции: +, -, *, /');
console.log('Введите "exit" для завершения');

const num1Str = await question('Первое число: ');
if (num1Str.toLowerCase() === 'exit') break;

const num2Str = await question('Второе число: ');
const operator = await question('Оператор (+, -, *, /): ');

const num1 = parseFloat(num1Str);
const num2 = parseFloat(num2Str);

if (isNaN(num1) || isNaN(num2)) {
console.log('Ошибка: Введены некорректные числа.');
continue;
}

try {
const result = calculate(num1, num2, operator);
console.log(`Результат: ${result}`);
} catch (err) {
console.log(`Ошибка: ${err.message}`);
}
}

readline.close();
console.log('Программа завершена.');
}

// Для запуска используйте: runCalculator();

Разбор логики

Интерфейс readline позволяет читать данные из стандартного потока ввода (stdin). Цикл while(true) поддерживает непрерывный режим работы программы. Функция parseFloat преобразует строки в числа с плавающей точкой. Конструкция switch реализует выбор математического действия. Проверка на NaN (Not a Number) предотвращает выполнение операций с некорректными данными.


Трекер задач в JSON

Трекер задач демонстрирует сериализацию объектов в формат JSON и десериализацию обратно, а также работу с файловой системой для сохранения состояния.

Основные концепции

  • JSON: Стандартный формат обмена данными между приложениями.
  • Сериализация: Преобразование объекта JavaScript в строку JSON.
  • Десериализация: Преобразование строки JSON обратно в объект.
  • Идентификаторы: Использование уникальных чисел для отслеживания задач.

Пример кода

const fs = require('fs').promises;
const path = require('path');

const DB_FILE = 'tasks.json';

class TaskTracker {
constructor() {
this.tasks = [];
}

async load() {
try {
const data = await fs.readFile(DB_FILE, 'utf-8');
this.tasks = JSON.parse(data);
} catch (error) {
// Если файл не существует, начинаем с пустого списка
if (error.code !== 'ENOENT') {
throw error;
}
this.tasks = [];
}
}

async save() {
const jsonContent = JSON.stringify(this.tasks, null, 2);
await fs.writeFile(DB_FILE, jsonContent, 'utf-8');
}

addTask(title, description = '') {
const task = {
id: Date.now(),
title: title,
description: description,
completed: false,
createdAt: new Date().toISOString()
};
this.tasks.push(task);
this.save();
console.log(`Задача #${task.id} добавлена.`);
}

listTasks() {
if (this.tasks.length === 0) {
console.log('Список задач пуст.');
return;
}
this.tasks.forEach(task => {
const status = task.completed ? '[x]' : '[ ]';
console.log(`${status} #${task.id}: ${task.title}`);
});
}

toggleTask(id) {
const task = this.tasks.find(t => t.id === id);
if (task) {
task.completed = !task.completed;
this.save();
console.log(`Статус задачи #${id} изменен.`);
} else {
console.log(`Задача #${id} не найдена.`);
}
}
}

// Пример использования
async function main() {
const tracker = new TaskTracker();
await tracker.load();

tracker.addTask('Изучить Node.js', 'Прочитать документацию и написать код');
tracker.listTasks();
tracker.toggleTask(Date.now()); // Здесь ID должен быть реальным, полученным ранее

console.log('Текущее состояние трекера сохранено в tasks.json');
}

// main();

Разбор логики

Класс TaskTracker инкапсулирует состояние и методы работы с данными. Метод load пытается прочитать файл, если файл отсутствует, создается пустой массив. Объекты задач содержат метаданные: уникальный идентификатор на основе текущего времени, описание и статус выполнения. Метод JSON.stringify превращает массив объектов в читаемую строку для хранения на диске.


Простой HTTP-сервер и клиент

Этот пример демонстрирует создание сетевого взаимодействия без использования внешних фреймворков, используя только встроенный модуль http.

Основные концепции

  • Сервер: Обработка входящих запросов и отправка ответов.
  • Клиент: Отправка запросов к серверу и получение данных.
  • Модуль http: Создание объектов Server и ClientRequest.
  • Обработчики событий: Реакция на события request, response, data, end.

Пример кода (Сервер)

const http = require('http');

const PORT = 3000;

const server = http.createServer((req, res) => {
console.log(`Запрос: ${req.method} ${req.url}`);

res.writeHead(200, { 'Content-Type': 'application/json' });

if (req.url === '/') {
res.end(JSON.stringify({ message: 'Добро пожаловать на сервер!' }));
} else if (req.url.startsWith('/api/data')) {
const responseData = {
timestamp: new Date().toISOString(),
status: 'active'
};
res.end(JSON.stringify(responseData));
} else {
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Ресурс не найден');
}
});

server.listen(PORT, () => {
console.log(`Сервер запущен на порту ${PORT}`);
});

Пример кода (Клиент)

const http = require('http');

function fetchData(url) {
return new Promise((resolve, reject) => {
const request = http.get(url, (res) => {
let data = '';

res.on('data', chunk => {
data += chunk;
});

res.on('end', () => {
try {
const parsedData = JSON.parse(data);
resolve(parsedData);
} catch (e) {
resolve(data);
}
});
});

request.on('error', (error) => {
reject(error);
});
});
}

async function main() {
try {
const response = await fetchData('http://localhost:3000/api/data');
console.log('Полученные данные:', response);
} catch (error) {
console.error('Ошибка при получении данных:', error.message);
}
}

// main();

Разбор логики

Сервер слушает порт 3000 и обрабатывает каждый входящий запрос через колбэк-функцию. Метод res.writeHead устанавливает код ответа и заголовки. Клиент использует метод http.get для отправки запроса. Данные поступают частями, поэтому они накапливаются в переменной data внутри события data. После завершения передачи (event end) данные парсятся как JSON.


Отправитель HTTP-запросов (POST)

Расширенная версия клиента для отправки данных на сервер с использованием POST-метода.

Основные концепции

  • POST-запросы: Отправка данных на сервер для создания или обновления ресурсов.
  • Настройка заголовков: Указание типа контента (Content-Type).
  • Передача тела запроса: Отправка JSON-строки в теле сообщения.

Пример кода

const http = require('http');

function sendPostRequest(url, data) {
return new Promise((resolve, reject) => {
const postData = JSON.stringify(data);

const options = {
hostname: new URL(url).hostname,
port: new URL(url).port || 80,
path: new URL(url).pathname,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData)
}
};

const req = http.request(options, (res) => {
let body = '';

res.on('data', chunk => {
body += chunk;
});

res.on('end', () => {
resolve({ statusCode: res.statusCode, body });
});
});

req.on('error', (error) => {
reject(error);
});

req.write(postData);
req.end();
});
}

async function main() {
const payload = { username: 'user1', action: 'login' };
try {
const result = await sendPostRequest('http://localhost:3000/api/login', payload);
console.log('Статус ответа:', result.statusCode);
console.log('Тело ответа:', result.body);
} catch (error) {
console.error('Ошибка отправки:', error.message);
}
}

// main();

Разбор логики

Объект options содержит параметры соединения, включая метод POST. Значение Content-Length рассчитывается автоматически для корректной обработки данных сервером. Метод req.write передает тело запроса, а req.end завершает отправку.


Утилита для сканирования директорий

Инструмент для обхода файловой структуры и сбора информации о файлах и подпапках.

Основные концепции

  • Рекурсивный обход: Глубокий проход по вложенным папкам.
  • Статистика: Подсчет количества файлов, размер директории.
  • Фильтрация: Поиск файлов по расширению или имени.

Пример кода

const fs = require('fs').promises;
const path = require('path');

async function scanDirectory(dirPath, extensions = []) {
let files = [];
let directories = [];
let totalSize = 0;

try {
const items = await fs.readdir(dirPath, { withFileTypes: true });

for (const item of items) {
const fullPath = path.join(dirPath, item.name);

if (item.isDirectory()) {
directories.push(item.name);
const subFiles = await scanDirectory(fullPath, extensions);
files = files.concat(subFiles.files);
totalSize += subFiles.totalSize;
} else {
if (extensions.length === 0 || extensions.includes(path.extname(item.name))) {
const stats = await fs.stat(fullPath);
files.push({ name: item.name, path: fullPath, size: stats.size });
totalSize += stats.size;
}
}
}
} catch (error) {
console.error(`Ошибка доступа к директории ${dirPath}:`, error.message);
}

return { files, directories, totalSize };
}

async function main() {
const results = await scanDirectory('./docs', ['.txt', '.md']);

console.log(`Найдено файлов: ${results.files.length}`);
console.log(`Найдено папок: ${results.directories.length}`);
console.log(`Общий размер: ${(results.totalSize / 1024).toFixed(2)} KB`);

console.log('\nСписок файлов:');
results.files.forEach(f => console.log(`- ${f.name} (${f.size} байт)`));
}

// main();

Разбор логики

Функция использует рекурсию: при обнаружении поддиректории она вызывает сама себя. Параметр withFileTypes: true позволяет сразу определить тип объекта без дополнительных вызовов stat. Фильтрация по расширениям происходит перед добавлением файла в список.


Скрипт для создания резервного копирования файлов

Автоматизация процесса дублирования файлов с добавлением временной метки.

Основные концепции

  • Копирование файлов: Использование fs.copyFile или ручного чтения/записи.
  • Генерация имен: Добавление даты и времени к имени файла.
  • Обработка путей: Корректная работа с путями разных операционных систем.

Пример кода

const fs = require('fs').promises;
const path = require('path');
const { execSync } = require('child_process');

async function createBackup(sourcePath, backupDir) {
try {
// Проверка существования источника
await fs.access(sourcePath);

// Создание директории бэкапа, если её нет
await fs.mkdir(backupDir, { recursive: true });

const fileName = path.basename(sourcePath);
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupFileName = `${timestamp}_${fileName}`;
const backupPath = path.join(backupDir, backupFileName);

// Копирование файла
await fs.copyFile(sourcePath, backupPath);

console.log(`Бэкап создан: ${backupPath}`);

// Опционально: удаление старых бэкапов (например, старше 7 дней)
// Логика удаления требует дополнительного цикла по файлам в backupDir

} catch (error) {
console.error('Ошибка создания бэкапа:', error.message);
}
}

// Пример вызова
// createBackup('./important_file.txt', './backups');

Разбор логики

Метод copyFile выполняет эффективное копирование на уровне ОС. Имя файла формируется путем объединения текущей временной метки и оригинального имени. Директория recursive: true гарантирует создание всех необходимых промежуточных папок.


Мониторинг дискового пространства

Скрипт для проверки свободного места на дисках и уведомления при достижении порога заполнения.

Основные концепции

  • Системные вызовы: Использование модуля os для получения информации о дисках.
  • Пороговые значения: Сравнение текущего использования с заданным лимитом.
  • Вывод статистики: Форматированная таблица данных.

Пример кода

const os = require('os');

function checkDiskSpace() {
const platforms = ['linux', 'darwin']; // Linux и macOS
const platform = os.platform();

if (!platforms.includes(platform)) {
console.log('Модуль os.diskSpace работает некорректно на этой платформе (Windows).');
console.log('Для Windows требуется использование child_process.execSync.');
return;
}

const diskInfo = os.freemem();
const totalMem = os.totalmem();
const percentFree = ((diskInfo / totalMem) * 100).toFixed(2);

console.log(`\n=== Статус памяти ===`);
console.log(`Всего памяти: ${(totalMem / 1024 / 1024 / 1024).toFixed(2)} GB`);
console.log(`Свободно памяти: ${(diskInfo / 1024 / 1024 / 1024).toFixed(2)} GB`);
console.log(`Занято памяти: ${percentFree}% свободно`);

// Проверка дисков (Linux/macOS)
const mounts = os.mountinfo(); // Доступно в некоторых версиях Node.js, иначе через fs

// Альтернативный способ через child_process для точности
const { execSync } = require('child_process');
try {
const dfOutput = execSync('df -h').toString();
console.log('\n=== Статус дисков ===');
console.log(dfOutput);
} catch (e) {
console.log('Не удалось получить информацию о дисках через команду df.');
}
}

checkDiskSpace();

Разбор логики

Модуль os предоставляет базовую информацию о системе. Для детального анализа дисков часто требуется вызов системных утилит через execSync. Команда df -h выводит информацию в удобочитаемом формате. Скрипт объединяет данные из нескольких источников для полной картины.


Парсер URL и проверка доступности ресурса

Инструмент для разбора компонентов ссылки и проверки HTTP-статуса целевой страницы.

Основные концепции

  • URL API: Встроенный класс URL для парсинга ссылок.
  • HTTP-проверка: Отправка HEAD-запроса для минимизации трафика.
  • Валидация: Проверка корректности формата ссылки.

Пример кода

const http = require('http');
const https = require('https');
const { URL } = require('url');

function parseAndCheckUrl(targetUrl) {
return new Promise((resolve, reject) => {
let parsedUrl;

try {
parsedUrl = new URL(targetUrl);
} catch (e) {
reject(new Error('Некорректный формат URL'));
return;
}

const protocol = parsedUrl.protocol === 'https:' ? https : http;
const options = {
hostname: parsedUrl.hostname,
port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
path: parsedUrl.pathname,
method: 'HEAD', // Используем HEAD для экономии ресурсов
timeout: 5000
};

const req = protocol.request(options, (res) => {
resolve({
url: targetUrl,
status: res.statusCode,
headers: res.headers,
valid: res.statusCode >= 200 && res.statusCode < 400
});
});

req.on('error', (e) => {
resolve({
url: targetUrl,
status: null,
error: e.message,
valid: false
});
});

req.on('timeout', () => {
req.destroy();
resolve({
url: targetUrl,
status: null,
error: 'Таймаут запроса',
valid: false
});
});

req.end();
});
}

async function main() {
const testUrls = [
'https://example.com',
'http://invalid-domain-xyz.com',
'not-a-url'
];

for (const url of testUrls) {
try {
const result = await parseAndCheckUrl(url);
console.log(`URL: ${result.url}`);
console.log(`Статус: ${result.status || 'Ошибка'}`);
console.log(`Доступен: ${result.valid ? 'Да' : 'Нет'}`);
if (result.error) console.log(`Ошибка: ${result.error}`);
console.log('---');
} catch (err) {
console.log(`Ошибка парсинга для ${url}: ${err.message}`);
}
}
}

// main();

Разбор логики

Конструктор URL автоматически проверяет структуру строки. Объект options динамически выбирает протокол (http или https) и стандартные порты. Использование метода HEAD возвращает только заголовки, что быстрее полного скачивания. Обработка таймаута предотвращает зависание скрипта при медленных ответах.


Конвертер форматов дат

Утилита для перевода дат между различными строковыми представлениями без использования внешних библиотек.

Основные концепции

  • Объект Date: Работа с внутренним представлением времени.
  • Форматирование: Извлечение отдельных частей даты (год, месяц, день).
  • Парсинг: Преобразование строки в объект даты.
  • Локализация: Учет различий в форматах записи.

Пример кода

function formatDate(date, format = 'DD.MM.YYYY') {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');

const map = {
YYYY: year,
MM: month,
DD: day,
HH: hours,
mm: minutes,
ss: seconds
};

let result = format;
for (const key in map) {
result = result.replace(key, map[key]);
}
return result;
}

function parseDate(dateString, format = 'DD.MM.YYYY') {
const parts = format.match(/[DYM]+|[Hm]+|[Ss]+|[Aa]+/g);
const values = dateString.split(/[-/.:/ ]+/);

let year, month, day, hour, minute, second;

// Простая логика сопоставления для формата DD.MM.YYYY
if (format === 'DD.MM.YYYY') {
day = parseInt(values[0], 10);
month = parseInt(values[1], 10) - 1; // Месяцы с 0
year = parseInt(values[2], 10);
} else if (format === 'YYYY-MM-DD') {
year = parseInt(values[0], 10);
month = parseInt(values[1], 10) - 1;
day = parseInt(values[2], 10);
} else {
throw new Error('Неподдерживаемый формат парсинга');
}

const date = new Date(year, month, day);

if (isNaN(date.getTime())) {
throw new Error('Некорректная дата');
}

return date;
}

// Пример использования
const now = new Date();
console.log('Стандартный формат:', formatDate(now, 'YYYY-MM-DD HH:mm:ss'));
console.log('Европейский формат:', formatDate(now, 'DD.MM.YYYY'));

const parsed = parseDate('06.05.2026', 'DD.MM.YYYY');
console.log('Распарсенная дата:', formatDate(parsed));

Разбор логики

Функция formatDate заменяет плейсхолдеры в шаблоне на актуальные значения из объекта Date. Метод padStart обеспечивает двухзначное представление чисел (например, 05 вместо 5). Функция parseDate принимает строку и шаблон, разбивает строку разделителями и сопоставляет части с элементами шаблона.


Утилита для просмотра запущенных процессов

Инструмент для вывода списка активных процессов системы с их параметрами.

Основные концепции

  • Выполнение системных команд: Использование child_process для запуска утилит ОС.
  • Обработка вывода: Парсинг текста из терминальной команды.
  • Фильтрация: Поиск процессов по имени.

Пример кода

const { execSync } = require('child_process');
const os = require('os');

function getProcesses(filterName = '') {
let command;
let args;

const platform = os.platform();

if (platform === 'win32') {
command = 'wmic';
args = ['process', 'get', 'Name,PID,CPU,Memory'].join(' ');
} else {
// Linux / macOS
command = 'ps';
args = ['-ef'];
}

try {
const output = execSync(`${command} ${args}`, { encoding: 'utf-8' });
const lines = output.trim().split('\n');

const processes = [];

// Пропускаем заголовок (если есть)
const startLine = platform === 'win32' ? 1 : 1;

for (let i = startLine; i < lines.length; i++) {
const line = lines[i].trim();
if (!line) continue;

let processObj = {};

if (platform === 'win32') {
// Простой парсинг для wmic (может требовать доработки для сложных случаев)
const parts = line.split(/\s+/);
if (parts.length >= 2) {
processObj = {
name: parts[0],
pid: parts[1] || 'N/A',
cpu: parts[2] || 'N/A',
memory: parts[3] || 'N/A'
};
}
} else {
// Парсинг для ps -ef (UID PID PPID C STIME TTY TIME CMD)
const parts = line.split(/\s+/);
if (parts.length >= 7) {
processObj = {
uid: parts[0],
pid: parts[1],
ppid: parts[2],
time: parts[6], // Время выполнения
cmd: parts.slice(7).join(' ') // Команда
};
}
}

if (Object.keys(processObj).length > 0) {
if (filterName && !processObj.name?.includes(filterName) && !processObj.cmd?.includes(filterName)) {
continue;
}
processes.push(processObj);
}
}

return processes;

} catch (error) {
console.error('Ошибка выполнения команды:', error.message);
return [];
}
}

function displayProcesses(processes) {
console.table(processes);
}

// Пример вызова
const allProcs = getProcesses();
displayProcesses(allProcs.slice(0, 10)); // Показать первые 10

const nodeProcs = getProcesses('node');
if (nodeProcs.length > 0) {
console.log('\nНайдены процессы Node.js:');
displayProcesses(nodeProcs);
}

Разбор логики

Команды wmic (Windows) и ps (Unix-like) предоставляют детальную информацию о процессах. Скрипт определяет операционную систему и выбирает соответствующую команду. Вывод разбивается на строки, каждая строка анализируется для извлечения ключевых полей. Функция filterName позволяет сузить список до нужных процессов.


Характерный пример именно для JavaScript

Особенностью JavaScript является его способность работать в двух совершенно разных средах: браузере и сервере (Node.js). Ниже приведен пример кода, который демонстрирует эту универсальность. Этот скрипт может работать и в консоли браузера, и в терминале Node.js, так как использует стандартные глобальные объекты и функции, доступные в обоих окружениях.

Универсальный счетчик слов

// Этот код работает и в браузере, и в Node.js

function countWords(text) {
if (typeof text !== 'string') {
throw new Error('Входные данные должны быть строкой');
}

const words = text.trim().split(/\s+/);
const filteredWords = words.filter(word => word.length > 0);

return {
total: filteredWords.length,
unique: new Set(filteredWords).size,
list: filteredWords
};
}

// Режим выполнения
if (typeof window === 'undefined') {
// Мы находимся в Node.js
const textInput = "JavaScript - это язык программирования. JavaScript очень популярен.";
const result = countWords(textInput);

console.log('Текст:', textInput);
console.log('Всего слов:', result.total);
console.log('Уникальных слов:', result.unique);
console.log('Список слов:', result.list);
} else {
// Мы находимся в браузере
document.getElementById('result').innerText = JSON.stringify(countWords(document.getElementById('input').value));
}

Почему этот пример характерен

  1. Отсутствие зависимостей: Код не требует подключения внешних библиотек.
  2. Полиморфизм среды: Проверка typeof window === 'undefined' позволяет адаптировать поведение кода под среду выполнения.
  3. Работа с данными: Использует современные возможности ES6+ (Set, стрелочные функции, шаблонные строки).
  4. Читаемость: Синтаксис максимально приближен к естественному языку, что делает код понятным даже новичкам.

Этот подход позволяет создавать библиотеки, которые работают везде, где выполняется JavaScript, будь то мобильное устройство, сервер или браузер пользователя.


Освоение главы0%